﻿using System;

namespace Quail
{
    /// <summary>
    /// Wraps access to HTML input controls
    /// </summary>
    public class WebInput : WebControl 
    {
        private string _inputType;
        private WebControl _labelControl;

        /// <summary>
        /// Initializes a new instance of the WebInput class.
        /// </summary>
        /// <param name="container">The owning html container</param>
        /// <param name="selector">The jQuery selector for the control</param>
        public WebInput(WebControlContainer container, string selector)
            : base(container, selector)
        {
        }

        /// <summary>
        /// Initializes a new instance of the WebInput class.
        /// </summary>
        /// <param name="control">The control for which the WebInput should take over</param>
        public WebInput(WebControl control)
            : base(control)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="WebInput"/> class.
        /// </summary>
        public WebInput()
        {
        }

        /// <summary>
        /// Gets or sets the input value
        /// </summary>
        public virtual string Value
        {
            get
            {
                var task = BeginTask("Get Value");
                try
                {
                    string result;

                    if (Tag == "TEXTAREA")
                        result = Page.Browser.SeleniumInterface.GetValue(Locator);
                    else
                    {
                        switch (InputType)
                        {
                            case "checkbox":
                            case "radio":
                                result = Page.Browser.SeleniumInterface.GetAttribute(Locator + "@value");
                                break;
                            default:
                                result = Page.Browser.SeleniumInterface.GetValue(Locator);
                                break;
                        }
                    }

                    task.Finish(result);

                    return result;
                }
                catch (Exception e)
                {
                    task.Finish(e);
                    throw;
                }
            }

            set
            {
                if (value == null)
                    value = string.Empty;

                var task = BeginTask("Set Value");
                task.AddAttribute("Value", value);
                try
                {
                    Page.Browser.SeleniumInterface.Type(Locator, value);
                    task.Finish();
                }
                catch (Exception e)
                {
                    task.Finish(e);
                    throw;
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the item is checked or not (applies to radio group/checkbox)
        /// </summary>
        public virtual bool Checked
        {
            get
            {
                var task = ActiveTask.BeginTask("Get Checked");
                try
                {
                    var result = Page.Browser.SeleniumInterface.IsChecked(Locator);
                    task.Finish(result.ToString());
                    return result;
                }
                catch (Exception e)
                {
                    task.Finish(e);
                    throw;
                }
            }

            set
            {
                var task = BeginTask("Set Checked");
                task.AddAttribute("Checked", value.ToString());
                try
                {
                    var ischeckednow = Checked;

                    // setting the checked member doesn't fire the click event, which many radio buttons use instead of onchange
                    if (value != ischeckednow)
                        Click();
                    /*
                    if (value)
                        Page.Browser.Selenium.Check(Locator);
                    else
                        Page.Browser.Selenium.Uncheck(Locator);*/

                    task.Finish();
                }
                catch (Exception e)
                {
                    task.Finish(e);
                    throw;
                }
            }
        }

        /// <summary>
        /// Gets the type attribute value for the input control (text, checkbox, radio, image)
        /// </summary>
        public string InputType
        {
            get
            {
                if (_inputType == null)
                    _inputType = Attr(KnownAttribute.InputType);
                return _inputType;
            }
        }

        /// <summary>
        /// Gets the src attribute value (applicable to type=image)
        /// </summary>
        public string Src
        {
            get { return Attr(KnownAttribute.Src); }   
        }

        /// <summary>
        /// Gets the filename of the src attribute (applicable to type=image)
        /// </summary>
        public string Filename
        {
            get { return System.IO.Path.GetFileName(Src); }
        }

        /// <summary>
        /// Gets or sets the label for this control
        /// </summary>
        public virtual string Label
        {
            get
            {
                return LabelControl.Exists ? LabelControl.InnerText : string.Empty;
            }

            set
            {
                throw new NotImplementedException("Label set is not implemented");
            }
        }

        /// <summary>
        /// Gets the label control for this control
        /// </summary>
        public WebControl LabelControl
        {
            get
            {
                if (_labelControl == null)
                {
                    if (!string.IsNullOrEmpty(ID))
                        _labelControl = ((WebControlContainer)ParentControl).GetControl("label[for=" + ID + "]");

                    if (_labelControl == null || !_labelControl.Exists)
                    {
                        // this is a hack for radio groups
                        var sel = Selector;
                        var re = new System.Text.RegularExpressions.Regex(":eq\\(\\d+\\)$");
                        sel = re.Replace(sel, string.Empty);

                        _labelControl = ((WebControlContainer)ParentControl).GetControl("label:has(" + sel + "[value='" + Value + "'])");
                    }
                }
                
                return _labelControl;
            }
        }

        /// <summary>
        /// Types the value into an input text box one character at a time
        /// </summary>
        /// <param name="value">the value to type</param>
        public void Type(string value)
        {
            var task = BeginTask("Type");
            task.AddAttribute("Value", value);
            try
            {
                Clear();
                Browser.SeleniumInterface.Focus(Locator);
                Browser.SeleniumInterface.TypeKeys(Locator, value + "\0");

                task.Finish();
            }
            catch (Exception e)
            {
                task.Finish(e);
                throw;
            }
        }

        /// <summary>
        /// Clears the input control of any text
        /// </summary>
		public override void Clear()
		{
			Value = string.Empty;
		}
    }
}
